﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ImageProcessingLib
{
    /// <summary>
    /// Класс с описанием основных парметров изображения.
    /// </summary>
    public class BitmapInfo4
    {
        /// <summary>
        /// Ширина изображения в пикселах.
        /// </summary>
        public int Width { get; set; }

        /// <summary>
        /// Высота изображения в пикселах.
        /// </summary>
        public int Height { get; set; }

        /// <summary>
        /// Выравнивание изображение.
        /// </summary>
        public int Stride { get; set; }

        /// <summary>
        /// Массив цветов изображения в формате ARGB.
        /// </summary>
        public int[] ImageArray4 { get; set; }
    }

    /// <summary>
    /// Класс со вспомогательными функциями.
    /// </summary>
    public class Utils
    {
        /// <summary>
        /// Получить объект BitmapInfo4 по заданному Bitmap.
        /// </summary>
        /// <param name="bitmap">Объект Bitmap.</param>
        /// <returns>Объект BitmapInfo4.</returns>
        public static BitmapInfo4 GetBitmapInfo(Bitmap bitmap)
        {
            if (bitmap == null || bitmap.Width == 0 || bitmap.Height == 0)
                return null;

            Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
            System.Drawing.Imaging.BitmapData bitmapData = bitmap.LockBits(r, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            int size = Math.Abs(bitmapData.Stride) * bitmap.Height / 4;
            int[] imageArray = new int[size];
            System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, imageArray, 0, size);
            bitmap.UnlockBits(bitmapData); 

            return new BitmapInfo4
            {
                Width = bitmapData.Width,
                Height = bitmapData.Height,
                Stride = bitmapData.Stride,
                ImageArray4 = imageArray
            };
        }

        /// <summary>
        /// Создает изображение соглсано BitmapInfo4 объекту.
        /// </summary>
        /// <param name="bmi">Объект BitmapInfo4.</param>
        /// <returns>Объект Bitmap.</returns>
        public static Bitmap CreateBitmap(BitmapInfo4 bmi)
        {
            Bitmap bitmap = new Bitmap(bmi.Width, bmi.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
            Rectangle r = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
            System.Drawing.Imaging.BitmapData bitmapData = bitmap.LockBits(r, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            int size = Math.Abs(bitmapData.Stride) * bitmap.Height / 4;
            System.Runtime.InteropServices.Marshal.Copy(bmi.ImageArray4, 0, bitmapData.Scan0, size);
            bitmap.UnlockBits(bitmapData);

            return bitmap;
        }

        /// <summary>
        /// Проверяет границы допустимых значений для r, g, b и упаковывает эти значения в целочисленную переменную.
        /// </summary>
        /// <param name="a">Значение альфа канала.</param>
        /// <param name="r">Красная компонента цвета.</param>
        /// <param name="g">Зеленая компонента цвета.</param>
        /// <param name="b">Синяя компонента цвета.</param>
        /// <returns>Цвет как целочисленная переменая.</returns>
        public static int CutEdges(int a, int r, int g, int b)
        {
            if (r < 0) r = 0;
            if (g < 0) g = 0;
            if (b < 0) b = 0;

            if (r > 0xFF) r = 0xFF;
            if (g > 0xFF) g = 0xFF;
            if (b > 0xFF) b = 0xFF;

            return Pack(a, r, g, b);
        }

        /// <summary>
        /// Распаковывает значения a, r, g, b из целочисленной переменной.
        /// </summary>
        /// <param name="color">Целочисленная переменная, где хранятся зачения каждого цветового канала..</param>
        /// <param name="a">Значение альфа канала.</param>
        /// <param name="r">Красная компонента цвета.</param>
        /// <param name="g">Зеленая компонента цвета.</param>
        /// <param name="b">Синяя компонента цвета.</param>
        public static void Unpack(int color, out int a, out int r, out int g, out int b)
        {
            a = (color & (0xFF << 24)) >> 24;
            r = (color & (0xFF << 16)) >> 16;
            g = (color & (0xFF << 8)) >> 8;
            b = (color & 0xFF);
        }

        /// <summary>
        /// Упаковывает значения a, r, g, b в целочисленную переменную.
        /// </summary>
        /// <param name="a">Значение альфа канала.</param>
        /// <param name="r">Красная компонента цвета.</param>
        /// <param name="g">Зеленая компонента цвета.</param>
        /// <param name="b">Синяя компонента цвета.</param>
        /// <returns>Цвет как целочисленная переменая.</returns>
        public static int Pack(int a, int r, int g, int b)
        {
            return b | (g << 8) | (r << 16) | (a << 24);
        }
    }
}
